using System;
using System.IO;
using System.Reflection;
using System.Xml;

namespace XmlObjects.XmlDocumentMarkup
{
	public class StringElementReader : AttributeReader<string>
	{
//		protected override string GetTheValue(string stringValue)
//		{
//			return stringValue;
//		}
	}

	public class DateTimeReader : AttributeReader<DateTime>
	{
//		protected override DateTime GetTheValue(string stringValue)
//		{
//			return string.IsNullOrEmpty(stringValue) ? DateTime.MinValue : DateTime.Parse(stringValue);
//		}
	}

	public class InstantiableReader<T> : AttributeReader<T> 
	{
		private ConstructorInfo info;

		public InstantiableReader()
		{
			Type theType = typeof (T);
			info = theType.GetConstructor(new Type[] {typeof (string)});
		}

//		protected override T GetTheValue(string stringValue)
//		{
//			return (T) info.Invoke(new object[] {stringValue});
//		}
	}

	public class ParseableReader<T> : AttributeReader<T>
	{
//		protected override T GetTheValue(string stringValue)
//		{
//			Type type = typeof (T);
//			object o = Activator.CreateInstance(type);
//			MethodInfo parseMethod = type.GetMethod("Parse", BindingFlags.Static);
//			return (T) parseMethod.Invoke(o, null);
//		}
	}

	public abstract class AttributeReader<T> : IXmlDocumentPropertyReader
	{
		private PropertyInfo propertyInfo;
		private string attributeName;
		public AttributeReader()
		{
			
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="propertyInfo">PropertyInfo object representing the property on the object</param>
		public AttributeReader(PropertyInfo propertyInfo)
		{
			this.propertyInfo = propertyInfo;
			XmlAttributeAttribute attribute = (XmlAttributeAttribute)propertyInfo.GetCustomAttributes(typeof(XmlAttributeAttribute), true)[0];
			attributeName = attribute.Name;
		}

		public void WriteXml(XmlNode node, DocumentElement theObject, XmlDocument ownerDocument)
		{
			XmlAttribute theAttribute = null;
			foreach (XmlAttribute anAttribute in node.Attributes)
			{
				if (attributeName.Equals(anAttribute.Name))
				{
					theAttribute = anAttribute;
				}
			}

			if (null==theAttribute)
			{
				theAttribute = ownerDocument.CreateAttribute(attributeName);
				node.Attributes.Append(theAttribute);
			}
			theAttribute.Value = propertyInfo.GetValue(theObject, null).ToString();
		}

		public void ReadXml(XmlNode node, object theObject)
		{
			string stringValue = node.Attributes[attributeName].Value;
			if (theObject != null) propertyInfo.SetValue(theObject, GetTheValue(stringValue), null);
		}

//		protected abstract T GetTheValue(string stringValue);

		protected object GetTheValue(string stringValue)
		{
			object theValue = null;

			if (propertyInfo.PropertyType == typeof(string))
				theValue = stringValue;
			else if (propertyInfo.PropertyType == typeof(int))
				theValue =  stringValue == null ? 0 : int.Parse(stringValue);
			else if (propertyInfo.PropertyType == typeof(float))
				theValue = stringValue == null ? 0 : float.Parse(stringValue);
			else if (propertyInfo.PropertyType == typeof(decimal))
				theValue = stringValue == null ? 0 : decimal.Parse(stringValue);
			else if (propertyInfo.PropertyType == typeof(double))
				theValue = stringValue == null ? 0 : double.Parse(stringValue);
			else if (propertyInfo.PropertyType == typeof(DateTime))
				theValue = stringValue == null ? DateTime.MinValue : DateTime.Parse(stringValue);
			else if (propertyInfo.PropertyType == typeof(FileInfo))
				theValue = stringValue == null ? null : new FileInfo(stringValue);
			return theValue;
		}
	}
}